package com.yu.waterstation.app.moudles.student.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yu.waterstation.app.moudles.address.mapper.AddressMapper;
import com.yu.waterstation.common.common.util.ip.IpUtil;
import com.yu.waterstation.common.entity.app.Address;
import com.yu.waterstation.app.moudles.student.mapper.StudentMapper;
import com.yu.waterstation.common.entity.app.Student;
import com.yu.waterstation.common.entity.app.dto.StudentDTO;
import com.yu.waterstation.common.entity.app.form.*;
import com.yu.waterstation.common.common.config.property.WeixinProperty;
import com.yu.waterstation.common.common.exception.ServiceException;
import com.yu.waterstation.common.common.util.GeneratorUtil;
import com.yu.waterstation.common.common.util.http.HttpUtil;
import com.yu.waterstation.common.common.util.result.Result;
import com.yu.waterstation.app.common.util.session.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;


@Slf4j
@Service
public class StudentServiceImpl implements StudentService {

    @Resource
    private WeixinProperty wxProperty;

    @Resource
    private StudentMapper studentMapper;

    @Resource
    private AddressMapper addressMapper;

    @Override
    public Result<StudentDTO> loginByWx(WeixinLoginForm weixinLoginForm) {
        String openid = getWeiXinOpenid(weixinLoginForm.getWxCode());
        if (openid == null)
            return Result.fail("微信登录失败");

        Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("wx_openid", openid));
        // 第一次登录时 自动注册
        if (student == null) {
            student = new Student();
            student.setWxOpenid(openid);
            student.setWxAvatar(weixinLoginForm.getWxAvatar());
            student.setStatus(true);
            studentMapper.insert(student);
        } else {
            // 检查账号是否冻结
            if (!student.getStatus())
                return Result.fail("账号已被冻结");
            student.setWxAvatar(weixinLoginForm.getWxAvatar());
            studentMapper.updateById(student); // 更新微信头像
        }

        StudentDTO studentDTO = getStudentInfo(student.getId());
        SessionUtil.setStudentSession(studentDTO);
        return Result.ok(studentDTO);

    }

    /**
     * 根据code获取微信openid
     *
     * @param code
     * @return
     */
    private String getWeiXinOpenid(String code) {
        String urlStr = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxProperty.getAppid()
                + "&secret=" + wxProperty.getAppSecret()
                + "&grant_type=authorization_code&js_code=" + code;
        String html = HttpUtil.getHtml(urlStr);
        JSONObject result = JSON.parseObject(html);
        Integer errcode = result.getInteger("errcode");
        if (errcode == null || errcode.equals(0))
            return result.getString("openid");
        else {
            log.error("[获取openid失败] 回复报文:{}", html);
            return null;
        }
    }

    // 获取用户的详细信息
    @Override
    public StudentDTO getStudentInfo(Integer id) {
        Student student = studentMapper.selectById(id);
        StudentDTO studentDTO = new StudentDTO();
        studentDTO.setId(student.getId());
        studentDTO.setUsername(student.getUsername());
        studentDTO.setWxOpenid(student.getWxOpenid());
        studentDTO.setPassword("******");
        studentDTO.setAddressId(student.getAddressId());
        studentDTO.setName(student.getName());
        studentDTO.setSex(student.getSex());
        studentDTO.setStatus(student.getStatus());
        studentDTO.setWxAvatar(student.getWxAvatar());
        studentDTO.setAddress(addressMapper.selectById(student.getAddressId()));
        return studentDTO;
    }

    /**
     * 绑定微信
     */
    @Transactional
    @Override
    public String bindWeiXin(Integer studentId, WeixinLoginForm form) throws ServiceException {
        String openid = getWeiXinOpenid(form.getWxCode());
        if (openid != null) {
            studentMapper.deleteOpenid(openid); // 先解绑之前的
            Student student = new Student();
            student.setId(studentId);
            student.setWxOpenid(openid);
            student.setWxAvatar(form.getWxAvatar());
            studentMapper.updateById(student);
            return openid;
        } else {
            throw ServiceException.CONST_bind_wei_xin_failed;
        }
    }

    @Transactional
    @Override
    public int updatePassword(Integer studentId, UpdatePasswordForm vo) throws Exception {
        if (StringUtils.isEmpty(vo.getOldPassword()) || StringUtils.isEmpty(vo.getNewPassword())
                || vo.getNewPassword().length() < 6 || vo.getNewPassword().length() > 18)
            throw ServiceException.CONST_password_not_validate;

        if (vo.getOldPassword().equals(vo.getNewPassword()))
            throw ServiceException.CONST_new_password_can_not_equals_old_password;

        Student student = studentMapper.selectById(studentId);
        if (!GeneratorUtil.md5Base64(vo.getOldPassword()).equals(student.getPassword()))
            throw ServiceException.CONST_old_password_error;

        student.setPassword(GeneratorUtil.md5Base64(vo.getNewPassword()));
        return studentMapper.updateById(student);
    }

    /**
     * 微信授权修改密码
     *
     * @param studentId
     * @param vo
     * @return
     * @throws Exception
     */
    @Transactional
    @Override
    public int updatePasswordByWeiXin(Integer studentId, UpdatePasswordByWeiXinForm vo) throws Exception {
        if (StringUtils.isEmpty(vo.getNewPassword())
                || vo.getNewPassword().length() < 6 || vo.getNewPassword().length() > 18)
            throw ServiceException.CONST_password_not_validate;
        Student student = studentMapper.selectById(studentId);
        if (GeneratorUtil.md5Base64(vo.getNewPassword()).equals(student.getPassword()))
            throw ServiceException.CONST_new_password_can_not_equals_old_password;
        if (student.getWxOpenid() == null)
            throw ServiceException.CONST_user_not_bind_wei_xin;

        String openid = getWeiXinOpenid(vo.getWxCode());
        if (openid != null) {
            if (!openid.equals(student.getWxOpenid())) { // 验证openid
                log.error("[账号绑定的openid[{}] 验证的openid[{}]", student.getWxOpenid(), openid);
                throw ServiceException.CONST_wx_validate_failed;
            }

            student.setPassword(GeneratorUtil.md5Base64(vo.getNewPassword()));
            return studentMapper.updateById(student);
        }
        throw ServiceException.CONST_wx_validate_failed;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateStudent(Integer studentId, UpdateStudentForm form) throws ServiceException {
        Student student = studentMapper.selectById(studentId);
        if (student == null)
            throw ServiceException.CONST_user_not_exist;

        student.setName(form.getName());
        student.setSex(form.getSex());
        student.setWxAvatar(form.getWxAvatar());
        return studentMapper.updateById(student);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Address setAddress(Integer studentId, Integer addressId) throws Exception {
        StudentDTO studentInfo = getStudentInfo(studentId);
        if (studentInfo.getAddressId() != null && studentInfo.getAddress() != null)
            throw ServiceException.CONST_student_has_address;

        Address address = addressMapper.selectById(addressId);
        if (address == null)
            throw ServiceException.CONST_address_not_exist;

        Student student = new Student();
        student.setId(studentId);
        student.setAddressId(addressId);
        studentMapper.updateById(student);
        return address;
    }

    @Transactional(rollbackFor =  Exception.class)
    @Override
    public Result<StudentDTO> loginByStudentNoAndPassword(StudentLoginForm loginForm, String ip) {
        Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("username", loginForm.getUsername()));
        if (student == null) { // 自动注册
            Integer count = studentMapper.selectCount(new QueryWrapper<Student>().eq("register_ip", ip));
            if(count > 0)
                return Result.fail("您已经注册过账号了，请勿重复注册"); // TODO 一个ip就只能注册一个账号
            student = new Student();
            if (StringUtils.isEmpty(loginForm.getPassword()) || loginForm.getPassword().length() < 4 || loginForm.getPassword().length() > 18)
                return Result.fail("密码长度只能在4-18之间");
            student.setUsername(loginForm.getUsername());
            student.setName(student.getUsername());
            student.setPassword(GeneratorUtil.md5Base64(loginForm.getPassword()));
            student.setStatus(true);
            student.setRegisterIp(ip);
            studentMapper.insert(student);
        } else {
            if (!student.getPassword().equals(GeneratorUtil.md5Base64(loginForm.getPassword())))
                return Result.fail("密码错误");
            if (!student.getStatus())
                return Result.fail("账号已被冻结");
        }
        StudentDTO studentDTO = new StudentDTO();
        studentDTO.setId(student.getId());
        studentDTO.setUsername(student.getUsername());
        studentDTO.setWxOpenid(student.getWxOpenid());
        studentDTO.setPassword("******");
        studentDTO.setAddressId(student.getAddressId());
        studentDTO.setName(student.getName());
        studentDTO.setSex(student.getSex());
        studentDTO.setStatus(student.getStatus());
        studentDTO.setWxAvatar(student.getWxAvatar());
        studentDTO.setAddress(addressMapper.selectById(student.getAddressId()));
        SessionUtil.setStudentSession(studentDTO);
        return Result.ok(studentDTO);
    }

}
